import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
	
public class XmlReader {
	
	private Config config;
	private Mail mail;

	
	public XmlReader(){
		config = new Config();
	}
	
	/** Gets data from a configuration XML file. Returns the new configuration data as object of type "Config".
	 * 
	 * @param filepath The path to the configuration XML file.
	 * @return Returns the current ( new ) configuration as object of type "Config".
	 * @throws FileNotFoundException
	 */
	public Config setConfig (String filepath) throws FileNotFoundException {
						
		try {
			  // Test whether the config file exists
			  boolean exists = (new File(filepath)).exists();
			  if (exists) { // Configuration file exists
 
				  // Read file and get root element
				  File file = new File(filepath);
				  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
				  DocumentBuilder db = dbf.newDocumentBuilder();
				  Document doc = db.parse(file);
				  doc.getDocumentElement().normalize();
				   
				  // Set Greylist
				  setConfigList("greylist",doc);
				  // Set Whitelist
				  setConfigList("whitelist",doc);
				 
				  // Set Technik
				  setConfigFakultaet("technik",doc);
				  // Set Wirtschaft
				  setConfigFakultaet("wirtschaft",doc);
				  // Set Sozialwesen
				  setConfigFakultaet("sozialwesen",doc);
				  // Set Ressorts
				  setConfigFakultaet("ressorts",doc);
				  
				  
			  } else { // Configuration file does not exist
				  System.out.println("Configuration file could not be found.");
				  // Stop the execution of the program
				  throw new FileNotFoundException();
			  }
		  } catch (Exception e) {
			    e.printStackTrace();
	    }
		
		return this.config;
	}

	/** Gets data from the child nodes of "greylist" or "whitelist" nodes.
	 * 
	 * @param nodeName A String that contains either "greylist" or "whitelist.
	 * @param doc The XML document as object of type "Document".
	 */
	private void setConfigList(String nodeName, Document doc){
		
		  NodeList list = doc.getElementsByTagName(nodeName).item(0).getChildNodes();
		  ArrayList<String> arraylist = new ArrayList<String>();
		  
		  for(int i=0; i<list.getLength(); i++) {
			  if(list.item(i).getNodeName()!="#text"){
				  arraylist.add(list.item(i).getTextContent().toLowerCase());	  
			  }  
		  }
		  
		  if(nodeName.equals("greylist")){
			  this.config.setGreylist(arraylist);
		  }
		  else if(nodeName.equals("whitelist")){
			  this.config.setWhitelist(arraylist);
		  }
		  else{
			  System.out.println("ERROR: '"+nodeName+"' is not a node specified for this program's configuration XML file. Based on its position, I assume it should be named 'greylist' or 'whitelist'. Cannot read data from this node." );
		  }
	}
	
	/** Gets data from the child nodes of "technik","wirtschaft","sozialwesen" or "ressort" nodes.
	 * 
	 * @param nodeName A String that contains either technik","wirtschaft","sozialwesen" or "ressort".
	 * @param doc The XML document as object of type "Document".
	 */
	private void setConfigFakultaet(String nodeName, Document doc){
		NodeList list = doc.getElementsByTagName(nodeName).item(0).getChildNodes();		
		ArrayList<String> mitarbeiter = new ArrayList<String>();
		ArrayList<String> abteilung = new ArrayList<String>();
		
		for(int i=0; i<list.getLength(); i++) {
			 if(list.item(i).getNodeName()!="#text"){
 			    if(list.item(i).getNodeName().equals("mitarbeiter")){
				    mitarbeiter.add(list.item(i).getTextContent().toLowerCase());
			    }
			    else if(list.item(i).getNodeName().equals("abteilung")){
			  	    abteilung.add(list.item(i).getTextContent().toLowerCase());
			    }
			    else{
				    System.out.println("ERROR: '"+list.item(i).getNodeName()+"' is not a node specified for this program's configuration XML file. Based on its position, I assume it should be named 'mitarbeiter' or 'abteilung'. Cannot read data from this node." );
			    }
			 }
		}
		
		
		
		if(nodeName.equals("technik")){
			this.config.setMitarbeiter_technik(mitarbeiter);
			this.config.setStudiengaenge_technik(abteilung);
		}
		else if(nodeName.equals("wirtschaft")){
			this.config.setMitarbeiter_wirtschaft(mitarbeiter);
			this.config.setStudiengaenge_wirtschaft(abteilung);
		}
		else if(nodeName.equals("sozialwesen")){
			this.config.setMitarbeiter_sozialwesen(mitarbeiter);
			this.config.setStudiengaenge_sozialwesen(abteilung);
		}
		else if(nodeName.equals("ressorts")){
			this.config.setMitarbeiter_ressorts(mitarbeiter);
			this.config.setRessorts(abteilung);
		}
		else{
			System.out.println("ERROR: '"+nodeName+"' is not a node specified for this program's configuration XML file. Based on its position, I assume it should be named either 'technik','wirtschaft','sozialwesen' or 'ressort'. Cannot read data from this node or its child nodes." );
		}	
	}

	/** Gets data from an email data XML file. Returns the read data as object of type "Mail".
	 * 
	 * @param filepath The path to the mail data XML file.
	 * @return Returns The read data as object of type "Mail".
	 * @throws FileNotFoundException
	 */
	public Mail readMail(String filepath) throws FileNotFoundException {
		mail = new Mail();
		
		try {
			  // Test whether the mail data exists
			  boolean exists = (new File(filepath)).exists();
			  if (exists) { // Mail data file exists
				  
				  // Read file and get root element
				  File file = new File(filepath);
				  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
				  DocumentBuilder db = dbf.newDocumentBuilder();
				  Document doc = db.parse(file);
				  doc.getDocumentElement().normalize();
				  
				  // Set Absender
				  setMailAbsender(doc);
				  // Set Namen
				  setMailMetrik("name",doc);
				  // Set Inhalt
				  setMailMetrik("inhalt",doc);
				  // Set Betreff
				  setMailMetrik("betreff",doc);
				  
			  }else { // Mail data file does not exist
				  System.out.println("Mail data file could not be found.");
				  // Stop the execution of the program
				  throw new FileNotFoundException();
			  }
		}catch(Exception e){
			e.printStackTrace();
		}
		
		
		return this.mail;
	}
	
	/** Gets the sender's email address from the XML file.
	 * 
	 * @param doc The XML file as object of type "Document"
	 */
	private void setMailAbsender(Document doc){
		this.mail.setAbsender(doc.getElementsByTagName("absender").item(0).getTextContent());	
	}
	
	/** Gets data from the child nodes of "name","inhalt" or "betreff" nodes.
	 * 
	 * @param nodeName A String that contains either "name","inhalt" or "betreff" nodes.
	 * @param doc The XML file as object of type "Document".
	 */
	private void setMailMetrik(String nodeName, Document doc){
		NodeList datensatzListe = doc.getElementsByTagName(nodeName).item(0).getChildNodes();
		NodeList datensatz;
		ArrayList<Evidence> list = new ArrayList<Evidence>();
		
		Evidence evidenz;
		ArrayList<String> set; 
		
		  
		  for(int i=0; i<datensatzListe.getLength(); i++) {
			  if(datensatzListe.item(i).getNodeName()!="#text"){
				  // Create new Evidence object
				  evidenz = new Evidence();
				  // Fill Evidence object with data from XML file
				  datensatz = datensatzListe.item(i).getChildNodes();
				  for(int j=0; j<datensatz.getLength(); j++) {	
					  if(datensatz.item(j).getNodeName()!="#text"){
						  if(datensatz.item(j).getNodeName().equals("bezeichnung")){
							  set = new ArrayList<String>();
							  set.add(datensatz.item(j).getTextContent().toLowerCase());
							  evidenz.setSet(set);
						  }
						  else if(datensatz.item(j).getNodeName().equals("evidenz")){
							  evidenz.setValue(Double.parseDouble(datensatz.item(j).getTextContent()));
						  }
						  else{
							  System.out.println("ERROR: '"+datensatz.item(j).getNodeName()+"' is not a node specified for this mail data xml file of this program. Based on its position, I assume it should be named either 'bezeichnung' or 'evidenz'.Cannot read data from this node." );
						  }  
					  }
				  }
				  list.add(evidenz);
			  }  
		  }
		  
		  if(nodeName.equals("name")){
			  this.mail.setNames(list);
		  }
		  else if(nodeName.equals("inhalt")){
			  this.mail.setContents(list);
		  }
		  else if(nodeName.equals("betreff")){
			  this.mail.setSubjects(list);
		  }
		  else{
			  System.out.println("ERROR: '"+nodeName+"' is not a node specified for this mail data xml file of this program. Based on its position, I assume it should be named either 'name', 'inhalt' or 'betreff'.Cannot read data from this node and its child nodes." );
		  }
		  
	}
}